package Engine;

import Exception.ServiceException;
import PSQueue.AbstractMessage;
import PSQueue.AbstractPublication;
import PSQueue.PSMessage;
import PSQueue.PSPublication;
import Service.AbstractParameter;
import Service.Variable;

public class MetaScheduleProtocol {

     public static final String ServiceInstanceProperty = "MetaProtocol:ServiceInstanceID";
     public static final String ServiceNameProperty = "MetaProtocol:ServiceName";
     public static final String ActivityNameProperty = "MetaProtocol:ActivityName";
	 
     public static final String ActivityStartToken = "MetaProtocol:ActivityStart:";
     public static final String ActivityCompleteToken = "MetaProtocol:ActivityComplete:";  
     
     
     public static final String ServiceInvocationToken = "MetaProtocol:ServiceInvocationToken";
     public static final String ServiceParameterObject = "MetaProtocol:ServiceParameterObject";
     public static final String ServiceCompletionToken = "MetaProtocol:ServiceCompletionToken";
     public static final String ServiceExceptionToken = "MetaProtocol:ServiceExceptionToken";
     public static final String ServiceExceptionObject = "MetaProtocol:ServiceExceptionObject";    
     
     private static final String SeparatorToken = "###*^_^*###";
     
     private static String generateMessage(String instanceID, String serviceName) {
    	 assert instanceID!=null;
    	 assert serviceName!=null;
    	 return instanceID + SeparatorToken + serviceName; 
     }
     
     private static String extractInstanceID(String message) {
    	 assert message!=null;
    	 int index_off = message.indexOf(SeparatorToken);
    	 assert index_off >0;
    	 return message.substring(0, index_off);
     }
     
     private static String extractPackageName(String message) {
    	 assert message!=null;
    	 int index_off = message.indexOf(SeparatorToken);
    	 assert index_off>0;
    	 index_off += SeparatorToken.length();
    	 String subString = message.substring(index_off);
    	 index_off = subString.indexOf(SeparatorToken);
    	 return message.substring(0, index_off);
     }
     
     private static String extractServiceName(String message) {
    	 assert message!=null;
    	 int index_off = message.indexOf(SeparatorToken);
    	 assert index_off>0;
    	 index_off += SeparatorToken.length();
    	 String subString = message.substring(index_off);
    	 index_off = subString.indexOf(SeparatorToken);
    	 index_off += SeparatorToken.length();
    	 return subString.substring(index_off);
     }
     
     //for testing
     public static void main(String[] args) {
    	 String instanceID = "instance1";
    	 String activityName = "activity1";
    	 String message = generateMessage(instanceID,activityName);
    	 System.out.println(message);
    	 
    	 String t_instanceID = extractInstanceID(message);
    	 System.out.println(t_instanceID);
    	 
    	 String t_activityName = extractServiceName(message);
    	 System.out.println(t_activityName);
    	 
     }
     
     
     //protocol 1: invoke a service
     // Pub: Msg1 (ServiceStartToken, Type: String,  Value: Parent InstanceID + SeparatorToken + ServiceName)
     //      Msg2 (ParameterToken, type: OTHERS, Value: Parameter Object)
     public static AbstractPublication getServiceInvocationProtocl(String instanceID, String pkgName, String serviceName, AbstractParameter parameter) {
    	 assert instanceID!=null;
    	 assert serviceName!=null;
    	 assert parameter!=null;
    	 
    	 PSPublication pub = new PSPublication();
    	 
    	 PSMessage msg = new PSMessage();
    	 msg.setMsgName(ServiceInvocationToken);
    	 msg.setMsgType(Variable.STRING);
    	 String value = generateMessage(instanceID, pkgName);
    	 value = generateMessage(instanceID, serviceName);
    	 msg.setValue(value);
    	 pub.addMessage(msg);
    	 
    	 msg = new PSMessage();
    	 msg.setMsgName(ServiceParameterObject);
    	 msg.setMsgType(Variable.OTHERS);
    	 msg.setValue(parameter);
    	 pub.addMessage(msg);
    	 
    	 return pub;
     }
     
     public static boolean isServiceInvocationProtocol(AbstractPublication pub) {
    	 assert pub!=null;
    	 
    	 AbstractMessage msg = pub.getMessage(ServiceInvocationToken);
    	 return msg!=null;
     }
     
     public static String getServiceInvocaterInstanceID(AbstractPublication pub) {
    	 assert pub!=null;
    	 AbstractMessage msg = pub.getMessage(ServiceInvocationToken);
    	 assert msg!=null;
    	 
    	 String value = (String)msg.getValue();
    	 assert value!=null;
    	 return extractInstanceID(value);
     }
     
     public static String getInvokedServiceName(AbstractPublication pub) {
    	 assert pub!=null;
    	 AbstractMessage msg = pub.getMessage(ServiceInvocationToken);
    	 assert msg!=null;
    	 
    	 String value = (String)msg.getValue();
    	 assert value!=null;
    	 return extractServiceName(value);
     }
     
     public static String getPackageName(AbstractPublication pub) {
    	 assert pub!=null;
    	 AbstractMessage msg = pub.getMessage(ServiceInvocationToken);
    	 assert msg!=null;
    	 
    	 String value = (String)msg.getValue();
    	 assert value!=null;
    	 return extractPackageName(value);
     }
     
     public static AbstractParameter getProtocolParameter(AbstractPublication pub) {
    	 assert pub!=null;
    	 AbstractMessage msg = pub.getMessage(ServiceParameterObject);
    	 assert msg!=null;
    	 
    	 return (AbstractParameter)msg.getValue();
     }
     
     
     //protocol 2: return from invoking a service
     // pub: Msg1 (ServiceCompletionToken, Type: String, Value: InstanceID of invoked service)
     //      Msg2 (ParameterToken, type: OTHERS, Value: Parameter) 
     public static AbstractPublication getServiceCompletionProtocol(String instanceID, AbstractParameter parameter) {
    	 assert instanceID!=null;
    	 assert parameter!=null;
    	 
    	 PSPublication pub = new PSPublication();
    	 
    	 PSMessage msg = new PSMessage();
    	 msg.setMsgName(ServiceCompletionToken);
    	 msg.setMsgType(Variable.STRING);
    	 msg.setValue(instanceID);
    	 pub.addMessage(msg);
    	 
    	 msg = new PSMessage();
    	 msg.setMsgName(ServiceParameterObject);
    	 msg.setMsgType(Variable.OTHERS);
    	 msg.setValue(parameter);
    	 pub.addMessage(msg);
    	 
    	 return pub;
     }
     
     public static boolean isServiceCompletionProtocol(AbstractPublication pub) {
    	 assert pub!=null;
    	 
    	 AbstractMessage msg = pub.getMessage(ServiceCompletionToken);
    	 return msg!=null;
     }
     
     public static String getServiceCompletionInstanceID(AbstractPublication pub) {
    	 assert pub!=null;
    	 AbstractMessage msg = pub.getMessage(ServiceCompletionToken);
    	 assert msg!=null;
    	 
    	 return (String)msg.getValue();
     }

     //Protocol 3: exception from invoked service
     //pub Msg1: (ExceptionToken, Type: String, Value: InstanceID of invoked service)
     //    Msg2: (ExceptionObjectToken, Type: OTHERS, Value: ServiceException) 
     
     public static AbstractPublication getServiceExceptionProtocol(String instanceID, ServiceException thrownException) {
    	 assert instanceID!=null;
    	 assert thrownException!=null;
    	 
    	 PSPublication pub = new PSPublication();
    	 
    	 PSMessage msg = new PSMessage();
    	 msg.setMsgName(ServiceExceptionToken);
    	 msg.setMsgType(Variable.STRING);
    	 msg.setValue(instanceID);
    	 pub.addMessage(msg);
    	 
    	 msg = new PSMessage();
    	 msg.setMsgName(ServiceExceptionObject);
    	 msg.setMsgType(Variable.OTHERS);
    	 msg.setValue(thrownException);
    	 pub.addMessage(msg);
    	 
    	 return pub;
     }
     
	 public static boolean isServiceInvocationException(AbstractPublication pub) {
		// TODO Auto-generated method stub
		assert pub!=null;
		AbstractMessage msg = pub.getMessage(ServiceExceptionToken);
     	return msg!=null;		
	 }

	 public static ServiceException getServiceExceptionObject(AbstractPublication pub) {
		// TODO Auto-generated method stub
		 assert pub!=null;
		 AbstractMessage msg = pub.getMessage(ServiceExceptionObject);
		 assert msg!=null;
		 return (ServiceException) msg.getValue();
	 }

	 public static String getServiceExceptionSourceInstanceID(AbstractPublication pub) {
		// TODO Auto-generated method stub
		 assert pub!=null;
		 AbstractMessage msg = pub.getMessage(ServiceExceptionToken);
		 assert msg!=null;
		 return (String) msg.getValue();
	 }
     
}
